package ChaiPiao;

import ChaiPiao.util.CombineUtil;

import java.util.ArrayList;
import java.util.List;

public class GameTicketSplitter {
    private List<Game> gameList;

    public GameTicketSplitter() {
        this.gameList = new ArrayList<>();
    }

    ;


    /************************************************methods**********************************************/

    /**
     * same game will not be added
     *
     * @param game
     */
    public void add(Game game) {
        if (!gameList.contains(game)) {
            this.gameList.add(game);
        }
    }

    /**
     * remove all the same game
     *
     * @param game
     */
    public void remove(Game game) {
        List<Game> listToRemove = new ArrayList<>();
        this.gameList.forEach((g) -> {
            if (g.equals(game))
                listToRemove.add(g);
        });
        this.gameList.removeAll(listToRemove);
    }


    private List<int[]> calcGameCombination(int n) {
        List<Integer> danGameIndexes = new ArrayList<>();
        List<Integer> notDanGameIndexes = new ArrayList<>();
        for (int i = 0; i < gameList.size(); ++i) {
            if (gameList.get(i).isSetDan())
                danGameIndexes.add(i);
            else
                notDanGameIndexes.add(i);
        }

        if (danGameIndexes.size() >= n) {
            throw new RuntimeException("非设胆赛事数目不满足当前的串关方式");
        }

        int[] indexes = new int[notDanGameIndexes.size()];
        for (int i = 0; i < notDanGameIndexes.size(); ++i) {
            indexes[i] = notDanGameIndexes.get(i);
        }
        if (n - danGameIndexes.size() > indexes.length)
            throw new RuntimeException("串方式基数减去设胆赛事数目大于非设胆赛事数目");
        List<int[]> list = CombineUtil.combine(indexes, n - danGameIndexes.size());

        for (int i = 0; i < list.size(); ++i) {
            int count = 0;
            indexes = new int[n];
            for (int j = 0; j < danGameIndexes.size(); ++j) {
                indexes[count] = danGameIndexes.get(j);
                count++;
            }
            for (int j = 0; j < list.get(i).length; ++j) {
                indexes[count] = list.get(i)[j];
                count++;
            }
            list.set(i, indexes);
        }
        return list;
    }

    private List<List<PlayTypeValuesEnumeration>> typeEnumerationsCombine(List<PlayTypeValuesEnumeration> enumerations, List<Integer> mixType_1) {
        List<List<PlayTypeValuesEnumeration>> result = new ArrayList<>();
        int[] indexes = new int[enumerations.size()];
        for (int i = 0; i < enumerations.size(); i++) {
            indexes[i] = i;
        }
        List<int[]> indexCombine = new ArrayList<>();
        for (int i : mixType_1) {
            indexCombine.addAll(CombineUtil.combine(indexes, i));
        }
        for (int[] combineIndexes : indexCombine) {
            List<PlayTypeValuesEnumeration> list = new ArrayList<>();
            for (int index : combineIndexes) {
                list.add(enumerations.get(index));
            }
            result.add(list);
        }
        return result;
    }

    private List<List<PlayTypeValuesEnumeration>> splitPlayTypeValueEnumeration(int mixTypeBase, List<Integer> mixType_1) {
        List<int[]> gameIndexesCombination = calcGameCombination(mixTypeBase);
        List<List<Game>> gameCombination = new ArrayList<>();
        for (int[] indexes : gameIndexesCombination) {
            List<Game> games = new ArrayList<>();
            for (int index : indexes) {
                games.add(this.gameList.get(index));
            }
            gameCombination.add(games);
        }

        List<List<PlayTypeValuesEnumeration>> playTypeValuesEnumerationListList = new ArrayList<>();
        for (List<Game> games : gameCombination) {
            Enumerator<PlayTypeValuesEnumeration> enumerator = new Enumerator<>();
            for (Game game : games) {
                enumerator.addEnumerable(game);
            }
            playTypeValuesEnumerationListList.addAll(enumerator.enumerate());
        }


        return playTypeValuesEnumerationListList;
    }

    public List<Ticket> splitTicket(int mixTypeBase, List<Integer> mixType_1) {
        List<Ticket> tickets = new ArrayList<>();
        List<List<PlayTypeValuesEnumeration>> playTypeValuesEnumerationListList = splitPlayTypeValueEnumeration(mixTypeBase, mixType_1);
        for (List<PlayTypeValuesEnumeration> enumerationList : playTypeValuesEnumerationListList) {
            List<List<PlayTypeValuesEnumeration>> typeEnumerationsCombination = this.typeEnumerationsCombine(enumerationList, mixType_1);
            Ticket ticket = new Ticket();
            for (List<PlayTypeValuesEnumeration> list : typeEnumerationsCombination) {
                ticket.addPlayTypeValuesCombination(list);
            }
            for (PlayTypeValuesEnumeration playTypeValuesEnumeration : enumerationList) {
                ticket.addPlayTypeValuesEnumeration(playTypeValuesEnumeration);
            }
            tickets.add(ticket);
        }
        return tickets;
    }

    public List<Note> splitNote(int mixTypeBase, List<Integer> mixType_1) {
        List<List<PlayTypeValuesEnumeration>> playTypeValuesEnumerationListList = this.splitPlayTypeValueEnumeration(mixTypeBase, mixType_1);
        List<Note> result = new ArrayList<>();
        for (List<PlayTypeValuesEnumeration> enumerations : playTypeValuesEnumerationListList) {
            List<List<PlayTypeValuesEnumeration>> typeEnumerationsCombination = this.typeEnumerationsCombine(enumerations, mixType_1);
            for (List<PlayTypeValuesEnumeration> enumerationList : typeEnumerationsCombination) {
                Enumerator<GameSelection> stringEnumerator = new Enumerator<>();
                for (PlayTypeValuesEnumeration enumeration : enumerationList) {
                    stringEnumerator.addEnumerable(enumeration);
                }
                List<List<GameSelection>> enumerateResult = stringEnumerator.enumerate();
                for (List<GameSelection> selectionList : enumerateResult) {
                    Note note = new Note();
                    for (GameSelection s : selectionList) {
                        note.addGameSelection(s);
                    }
                    result.add(note);
                }
            }
        }
        return result;
    }
}
